<p>A fluent interface designates an object-oriented API relying on method chaining to improve code readability. In such interfaces, methods return the
object <code>this</code> to allow the caller to chain multiple method invocations.</p>
<pre>
class RichText {
    constructor(private readonly text: string) {}
    bold(): RichText {
        // [...]
        return this;
    }
    italic(): RichText {
        // [...]
        return this;
    }
}

const richText = new RichText('Hello, World!');
// Chaining methods bold() and italic().
console.log(richText.bold().italic());
</pre>
<p>To better support fluent interfaces when used with a hierarchy of classes, TypeScript provides a special type <code>this</code> that refers
dynamically to the type of the current class.</p>
<p>Methods returning <code>this</code> should thus use the corresponding special type <code>this</code> instead of the class name in their
signatures.</p>
<h2>Why is this an issue?</h2>
<p>When a method return type is the declaring class name in a hierarchy of classes, it is impossible to chain methods defined in the superclass with
methods defined in subclasses.</p>
<pre>
enum Color {
    RED, BLUE, GREEN
}

class Shape {
    // The return type is the class name.
    move(x: number, y: number): Shape {
        // [...]
        return this;
    }
}

class Polygon extends Shape {
    fill(color: Color): Polygon {
        // [...]
        return this;
    }
}

const polygon = new Polygon();
polygon.move(1.0, 2.0).fill(Color.RED);
//                     ^^^^
//                     Property 'fill' does not exist on type 'Shape'.
</pre>
<h2>How to fix it</h2>
<p>When a method declaration uses the special type <code>this</code> instead of the class name for its return type, TypeScript will use the type of
the object <code>this</code> instead of the method declaring class and will accept to invoke methods defined in the object class:</p>
<pre>
enum Color {
    RED, BLUE, GREEN
}

class Shape {
    // The return type is now "this"
    move(x: number, y: number): this {
        // [...]
        return this;
    }
}

class Polygon extends Shape {
    fill(color: Color): this {
        // [...]
        return this;
    }
}

const polygon = new Polygon();
polygon.move(1.0, 2.0).fill(Color.RED); // No compilation error
</pre>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
class A {
  foo(): A { // Noncompliant
    return this;
  }
  bar = (): A =&gt; { // Noncompliant
    return this;
  };
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
class A {
  foo(): this {
    return this;
  }
  bar = (): this =&gt; {
    return this;
  };
}
</pre>
<h2>Resources</h2>
<h3>Documentation</h3>
<ul>
  <li> <a href="https://typescript-eslint.io/">typescript-eslint</a> - Rule <a
  href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-return-this-type.mdx">prefer-return-this-type</a> </li>
  <li> TypeScript Documentation - <a href="https://www.typescriptlang.org/docs/handbook/2/classes.html#this-types"><code>this</code> Types</a> </li>
  <li> Wikipedia - <a href="https://en.wikipedia.org/wiki/Fluent_interface">Fluent interface</a> </li>
</ul>
